#include "pch.h"

using std::stack;
using std::string;
using std::ifstream;
using std::pair;
using std::sort;

int Utils::winner_definite(const Board & board) {
	stack<int> st;
	
	bool vis[200] = { 0 };
	int u[6] = { 0,1,1,0,-1,-1 };
	int v[6] = { 1,0,-1,-1,0,1 };

	int size = board.s();

	for (int i = 0; i < size; i++) {
		if (board.get(i) == 1) {
			st.push(i);
			vis[i] = true;
		}
	}

	int flag = 0;
	while (!st.empty()) {
		int pos = st.top();
		st.pop();
		int px = pos / size;
		int py = pos % size;
		for (int i = 0; i < 6; i++) {
			int nx = px + u[i];
			int ny = py + v[i];
			int npos = nx * size + ny;
			if (nx >= 0 && nx < size && ny >= 0 && ny < size && !vis[npos] && board.get(nx, ny) == 1) {
				if (npos / size == size - 1) {
					flag = 1;
					break;
				}

				vis[npos] = true;
				st.push(npos);
			}
		}
	}

	return flag ? 1 : 2;
}

int Utils::winner(const Board & board) {
	static const int dir[6][2] = {
		0,-1,
	-1,0,
	-1,1,
	0,1,
	1,0,
	1,-1
	};

	int size = board.s();

	std::stack<int> q;
	int vis[20][20] = { 0 };
	for (int i = 0; i < size; i++)
	{
		if (board.get(i, 0) == 2)
		{
			q.push(i * size);
			vis[i][0] = 1;
		}
	}
	while (!q.empty())
	{
		int p = q.top();
		q.pop();
		int x = p / size;
		int y = p % size;
		for (int i = 0; i < 6; i++)
		{
			int nx = x + dir[i][0];
			int ny = y + dir[i][1];
			int npos = nx * size + ny;
			if (nx >= 0 && nx < size && ny >= 0 && ny < size && !vis[nx][ny] && board.get(nx, ny) == 2)
			{
				if (ny == size - 1)
				{
					return 2;
				}
				vis[nx][ny] = true;
				q.push(npos);
			}
		}
	}

	memset(vis, 0, sizeof(vis));
	for (int i = 0; i < size; i++)
	{
		if (board.get(0, i) == 1)
		{
			q.push(i);
			vis[0][i] = 1;
		}
	}
	while (!q.empty())
	{
		int p = q.top();
		q.pop();
		int x = p / size;
		int y = p % size;
		for (int i = 0; i < 6; i++)
		{
			int nx = x + dir[i][0];
			int ny = y + dir[i][1];
			if (nx >= 0 && nx < size && ny >= 0 && ny < size && !vis[nx][ny] && board.get(nx, ny) == 1)
			{
				if (nx == size - 1)
				{
					return 1;
				}
				vis[nx][ny] = true;
				q.push(nx * size + ny);
			}
		}
	}

	return 0;
}

pair<int, int> Utils::first_available_move(const Board & board) {
	int size = board.s();
	for (int i = 0; i < size; i++) {
		for (int j = 0; j < size; j++) {
			if (board.get(i, j) == Board::EMPTY) {
				return { i, j };
			}
		}
	}

	throw std::exception("no available move\n");
	return { 0, 0 };
}

bool Utils::is_loser_td(const Board & board, int to_play) {
	int size = board.s();

	int d1[200];
	int d2[200];
	TwoDistanceEngine bee(board);

	if (to_play == 1)
	{
		bee.left_up(d1);
		bee.right_down(d2);
	}
	else if (to_play == 2)
	{
		bee.left_down(d1);
		bee.right_up(d2);
	}

	int temp[200];
	memset(temp, INF, sizeof(temp));
	for (int i = 0; i < size * size; i++)
	{
		temp[i] = d1[i] + d2[i];
	}

	sort(temp, temp + size * size);
	if (temp[0] >= INF) {
		return true;
	}

	return false;
}

void Utils::fill_captured_and_dead(Board & board) {
	int out[200];
	int size = board.s();

	ICEngine::solve_captured_and_dead(board, out);
	for (int i = 0; i < size * size; i++) {
		if (out[i] == 1) {
			board.set(i, 1);
		}
		else if (out[i] == 2) {
			board.set(i, 2);
		}
	}
}

Board Utils::load_board_from_file(const std::string & filename) {
	ifstream file(filename);

	if (!file.is_open()) {
		printf("fail to open file %s\n", filename.c_str());
		throw std::exception("file open fail");
	}

	int size;
	file >> size;

	Board ans(size);

	for (int i = 0; i < size; i++) {
		for (int j = 0; j < size; j++) {
			char c;
			file >> c;
			ans.set(i, j, c - '0');
		}
	}

	return ans;
}

void Utils::print_board(const Board & board) {
	int size = board.s();
	for (int i = 0; i < size; i++) {
		for (int j = 0; j < i; j++) {
			printf(" ");
		}
		for (int j = 0; j < size; j++) {
			char c;
			if (board.get(i, j) == 0)
				c = '.';
			else if (board.get(i, j) == 1)
				c = '*';
			else
				c = 'o';

			printf("%c ", c);
		}
		printf("\n");
	}
}